package nfwx.wifi;

import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.wifi.ScanResult;
import android.net.wifi.SupplicantState;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Handler;
import android.util.Log;

import org.json.JSONArray;
import org.json.JSONObject;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.net.ssl.HttpsURLConnection;

/**
 * 南方无线电视WiFi自动认证连接管理器
 */

public class NFWXWiFiManager {
    /**
     * 当发现自动认证的WiFi时调用
     */
    public interface OnWiFiAvailableListener {
        void onWiFiAvailable(List<String> wifis);

        void onNoWiFi();

        void onWiFiConnected();

        void wifiNoEnable();
    }

    /**
     * 服务器接口地址
     */
    String _serverUrl;

    /**
     * 应用上下文
     */
    Context _ctx;

    Set<OnWiFiAvailableListener> _handlers;

    Handler _handler;
    Handler _handler2;

    boolean _running;
    boolean _started;

    static NFWXWiFiManager _instance;

    static final int SCAN_DELAY = 60000;

    final int NO_NETWORK = 0;
    final int WIFI_NETWORK = 1;
    final int G_NETWORK = 2;
    final int LINE_NETWORK = 3;

    private NFWXWiFiManager(Context ctx, String serverUrl) {
        _ctx = ctx;
        _serverUrl = serverUrl;
        _handlers = new HashSet<>();
        _handler = new Handler();
        _handler2 = new Handler();
    }

    /**
     * 初始化南方无线电视WiFi管理器
     *
     * @param ctx       应用上下文
     * @param serverUrl 服务器接口地址
     * @return
     */
    public static NFWXWiFiManager initialize(Context ctx, String serverUrl) {
        if (_instance != null) return _instance;
        _instance = new NFWXWiFiManager(ctx, serverUrl);
        return _instance;
    }

    /**
     * 单例接口
     *
     * @return
     */
    public static NFWXWiFiManager getInstance() {
        if (_instance == null) {
            throw new RuntimeException("initialize is not called");
        }
        return _instance;
    }

    /**
     * 添加WiFi可用事件监听器
     *
     * @param cb
     */
    public void addOnWiFiAvailableListener(OnWiFiAvailableListener cb) {
        if (cb == null) return;
        _handlers.add(cb);
    }

    /**
     * 移除WiFi可用事件监听器
     *
     * @param cb 监听器对象，如果为null则移除所有监听器
     */
    public void removeOnWiFiAvailableListener(OnWiFiAvailableListener cb) {
        if (cb == null) {
            _handlers.clear();
            return;
        }
        _handlers.remove(cb);
    }

    public static String httpGET(String url, Map<String, String> headers) {
        InputStream inputStream = null;
        URLConnection conn = null;
        try {
            URL u = new URL(url);
            conn = u.openConnection();
            if (conn instanceof HttpURLConnection) {
                HttpURLConnection http = (HttpURLConnection) conn;
                http.setRequestMethod("GET");
                http.setConnectTimeout(10000);
                if (headers != null) {
                    for (Map.Entry<String, String> kv : headers.entrySet()) {
                        http.setRequestProperty(kv.getKey(), kv.getValue());
                    }
                }
                http.connect();
                inputStream = http.getInputStream();
            } else if (conn instanceof HttpsURLConnection) {
                HttpsURLConnection https = (HttpsURLConnection) conn;
                https.setRequestMethod("GET");
                https.setConnectTimeout(10000);
                if (headers != null) {
                    for (Map.Entry<String, String> kv : headers.entrySet()) {
                        https.setRequestProperty(kv.getKey(), kv.getValue());
                    }
                }
                https.connect();
                inputStream = https.getInputStream();
            } else {
                throw new IOException("Not supported connection type");
            }
            BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
            String readerLine;
            StringBuffer buffer = new StringBuffer();
            while ((readerLine = reader.readLine()) != null) {
                buffer.append(readerLine);
            }
            return buffer.toString();
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }

    public static String httpGET(Context ctx, String url, Map<String, String> headers, int networkId) {
        ConnectivityManager connectivityManager = (ConnectivityManager) ctx.getSystemService(Context.CONNECTIVITY_SERVICE);
        InputStream inputStream = null;
        OutputStream out = null;
        URLConnection conn;
        try {
            URL u = new URL(url);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                conn = connectivityManager.getActiveNetwork().openConnection(u);
            } else {
                conn = u.openConnection();
            }
            if (conn instanceof HttpURLConnection) {
                HttpURLConnection http = (HttpURLConnection) conn;
                http.setRequestMethod("GET");
                http.setConnectTimeout(10000);
                if (headers != null) {
                    for (Map.Entry<String, String> kv : headers.entrySet()) {
                        http.setRequestProperty(kv.getKey(), kv.getValue());
                    }
                }
                http.connect();
                inputStream = http.getInputStream();
            } else if (conn instanceof HttpsURLConnection) {
                HttpsURLConnection https = (HttpsURLConnection) conn;
                https.setRequestMethod("GET");
                https.setConnectTimeout(10000);
                if (headers != null) {
                    for (Map.Entry<String, String> kv : headers.entrySet()) {
                        https.setRequestProperty(kv.getKey(), kv.getValue());
                    }
                }
                https.connect();
                inputStream = https.getInputStream();
            } else {
                throw new IOException("Not supported connection type");
            }
            BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
            String readerLine;
            StringBuffer buffer = new StringBuffer();
            while ((readerLine = reader.readLine()) != null) {
                buffer.append(readerLine);
            }
            return buffer.toString();
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }

    /**
     * HTTP响应
     */
    static class HttpResponse {
        final int code;
        final String body;

        HttpResponse(int code, String body) {
            this.code = code;
            this.body = body;
        }
    }

    public static int httpGETCode(String url) {
        InputStream inputStream = null;
        URLConnection conn = null;
        try {
            URL u = new URL(url);
            conn = u.openConnection();
            if (conn instanceof HttpURLConnection) {
                HttpURLConnection http = (HttpURLConnection) conn;
                http.setRequestMethod("GET");
                http.setConnectTimeout(10000);
                http.setInstanceFollowRedirects(false);
                http.setReadTimeout(10000);
                http.setUseCaches(false);
                http.connect();
                inputStream = http.getInputStream();
                return http.getResponseCode();
            } else if (conn instanceof HttpsURLConnection) {
                HttpsURLConnection https = (HttpsURLConnection) conn;
                https.setRequestMethod("GET");
                https.setConnectTimeout(10000);
                https.setConnectTimeout(10000);
                https.setInstanceFollowRedirects(false);
                https.setReadTimeout(10000);
                https.setUseCaches(false);
                https.connect();
                inputStream = https.getInputStream();
                return https.getResponseCode();
            } else {
                throw new IOException("Not supported connection type");
            }
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return -1;
    }

    public static String httpPOST(String url, String params, Map<String, String> headers) {
        InputStream inputStream = null;
        OutputStream out = null;
        URLConnection conn;
        try {
            URL u = new URL(url);
            conn = u.openConnection();
            if (conn instanceof HttpURLConnection) {
                HttpURLConnection http = (HttpURLConnection) conn;
                http.setRequestMethod("POST");
                http.setDoOutput(true);
                http.setDoInput(true);
                http.setConnectTimeout(10000);
                if (headers != null) {
                    for (Map.Entry<String, String> kv : headers.entrySet()) {
                        http.setRequestProperty(kv.getKey(), kv.getValue());
                    }
                }
                http.setRequestProperty("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
                http.setRequestProperty("Connection", "Keep-Alive");
                http.connect();
                out = http.getOutputStream();
                out.write(params.getBytes("UTF-8"));
                out.flush();
                out.close();
                out = null;
                int status = http.getResponseCode();
                if (status != HttpURLConnection.HTTP_OK)
                    inputStream = http.getErrorStream();
                else
                    inputStream = http.getInputStream();
                BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
                String readerLine;
                StringBuffer buffer = new StringBuffer();
                while ((readerLine = reader.readLine()) != null) {
                    buffer.append(readerLine);
                }
                return buffer.toString();
            } else if (conn instanceof HttpsURLConnection) {
                HttpsURLConnection https = (HttpsURLConnection) conn;
                https.setRequestMethod("POST");
                https.setDoOutput(true);
                https.setDoInput(true);
                https.setConnectTimeout(10000);
                if (headers != null) {
                    for (Map.Entry<String, String> kv : headers.entrySet()) {
                        https.setRequestProperty(kv.getKey(), kv.getValue());
                    }
                }
                https.setRequestProperty("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
                https.setRequestProperty("Connection", "Keep-Alive");
                https.connect();
                out = https.getOutputStream();
                out.write(params.getBytes("UTF-8"));
                out.flush();
                out.close();
                out = null;
                int status = https.getResponseCode();
                if (status != HttpURLConnection.HTTP_OK)
                    inputStream = https.getErrorStream();
                else
                    inputStream = https.getInputStream();
                BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
                String readerLine;
                StringBuffer buffer = new StringBuffer();
                while ((readerLine = reader.readLine()) != null) {
                    buffer.append(readerLine);
                }
                return buffer.toString();
            } else {
                throw new IOException("Not supported connection type");
            }

        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }

    public static String httpPOST(Context ctx, String url, String params, Map<String, String> headers, int networkId) {
        ConnectivityManager connectivityManager = (ConnectivityManager) ctx.getSystemService(Context.CONNECTIVITY_SERVICE);
        InputStream inputStream = null;
        OutputStream out = null;
        URLConnection conn;
        try {
            URL u = new URL(url);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                conn = connectivityManager.getActiveNetwork().openConnection(u);
            } else {
                conn = u.openConnection();
            }
            if (conn instanceof HttpURLConnection) {
                HttpURLConnection http = (HttpURLConnection) conn;
                http.setRequestMethod("POST");
                http.setDoOutput(true);
                http.setDoInput(true);
                http.setConnectTimeout(10000);
                if (headers != null) {
                    for (Map.Entry<String, String> kv : headers.entrySet()) {
                        http.setRequestProperty(kv.getKey(), kv.getValue());
                    }
                }
                http.setRequestProperty("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
                http.setRequestProperty("Connection", "Keep-Alive");
                http.connect();
                out = http.getOutputStream();
                out.write(params.getBytes("UTF-8"));
                out.flush();
                out.close();
                out = null;
                int status = http.getResponseCode();
                if (status != HttpURLConnection.HTTP_OK)
                    inputStream = http.getErrorStream();
                else
                    inputStream = http.getInputStream();
                BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
                String readerLine;
                StringBuffer buffer = new StringBuffer();
                while ((readerLine = reader.readLine()) != null) {
                    buffer.append(readerLine);
                }
                return buffer.toString();
            } else if (conn instanceof HttpsURLConnection) {
                HttpsURLConnection https = (HttpsURLConnection) conn;
                https.setRequestMethod("POST");
                https.setDoOutput(true);
                https.setDoInput(true);
                https.setConnectTimeout(10000);
                if (headers != null) {
                    for (Map.Entry<String, String> kv : headers.entrySet()) {
                        https.setRequestProperty(kv.getKey(), kv.getValue());
                    }
                }
                https.setRequestProperty("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
                https.setRequestProperty("Connection", "Keep-Alive");
                https.connect();
                out = https.getOutputStream();
                out.write(params.getBytes("UTF-8"));
                out.flush();
                out.close();
                out = null;
                int status = https.getResponseCode();
                if (status != HttpURLConnection.HTTP_OK)
                    inputStream = https.getErrorStream();
                else
                    inputStream = https.getInputStream();
                BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
                String readerLine;
                StringBuffer buffer = new StringBuffer();
                while ((readerLine = reader.readLine()) != null) {
                    buffer.append(readerLine);
                }
                return buffer.toString();
            } else {
                throw new IOException("Not supported connection type");
            }
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }


    /**
     * 开启WiFi扫描
     */
    public void start() {
        _started = true;
        if (Build.VERSION.SDK_INT >= 23) {

        }
        _doRun();
    }

    /**
     * 停止扫描
     */
    public void stop() {
        _started = false;
        _running = false;
        _handler.removeCallbacksAndMessages(null);
    }

    /**
     * 请求验证参数结果
     */
    interface OnMakeAuthResult {
        void onResult(JSONObject res);

        void onFailed(String msg);
    }

    /**
     * 内网认证
     *
     * @param ssid
     * @param accessToken
     * @param cb
     */
    void _makeAuthInHospitalNetwork(final String ssid, final String accessToken, final OnMakeAuthResult cb) {
        new AsyncTask<Void, Void, String>() {
            @Override
            protected String doInBackground(Void... params) {
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                String uParams = "SSID=" + URLEncoder.encode(ssid);
                Map<String, String> headers = new HashMap<String, String>();
                headers.put("Authorization", "Bearer " + accessToken);
                return httpPOST(_serverUrl + "/connection", uParams, headers);
            }

            @Override
            protected void onPostExecute(String s) {
                if (s == null) {
                    cb.onFailed("Network Error");
                    return;
                }
                JSONObject o;
                try {
                    if (s.contains("AUTH")) {
                        cb.onFailed(s);
                        return;
                    }
                    o = new JSONObject(s);
                } catch (Throwable e) {
                    cb.onFailed(e.getLocalizedMessage());
                    return;
                }
                cb.onResult(o);
            }
        }.execute();
    }


    /**
     * 外网认证
     *
     * @param ssid
     * @param accessToken
     * @param cb
     */
    void _makeAuth(final String ssid, final String accessToken, final OnMakeAuthResult cb) {
        _waitWiFiDiabled(50, new OnWiFiEnabled() {
            @Override
            public void onEnabled() {
                new AsyncTask<Void, Void, String>() {
                    @Override
                    protected String doInBackground(Void... params) {
                        String uParams = "SSID=" + URLEncoder.encode(ssid);
                        Map<String, String> headers = new HashMap<String, String>();
                        headers.put("Authorization", "Bearer " + accessToken);
                        return httpPOST(_serverUrl + "/connection", uParams, headers);
                    }

                    @Override
                    protected void onPostExecute(String s) {
                        if (s == null) {
                            cb.onFailed("Network Error");
                            return;
                        }
                        JSONObject o;
                        try {
                            o = new JSONObject(s);
                        } catch (Throwable e) {
                            cb.onFailed(e.getLocalizedMessage());
                            return;
                        }
                        cb.onResult(o);
                    }
                }.execute();
            }

            @Override
            public void onFailed(String msg) {
                cb.onFailed(msg);
            }
        });

    }

    /**
     * 连接到指定的WiFi
     *
     * @param ssid        要连接的免认证WiFi
     * @param accessToken 用户登录的accessToken
     */
    public void connect(final String ssid, final String accessToken, final OnWiFiEnabled cb) {
        final WifiManager mgr = (WifiManager) _ctx.getSystemService(Context.WIFI_SERVICE);
        final boolean lastWiFiEnabled = mgr.isWifiEnabled();
        final int networkId = mgr.getConnectionInfo().getNetworkId();
        if (getNetworkType(_ctx) == WIFI_NETWORK
                && mgr.getWifiState() == WifiManager.WIFI_STATE_ENABLED
                && networkId != -1) {
            _doAuthInHospitalNetwork(ssid, accessToken, cb, mgr, networkId, lastWiFiEnabled);
        } else {
            _doAuth(ssid, accessToken, cb, mgr, lastWiFiEnabled);
        }
    }

    /**
     * 内网认证Wifi
     *
     * @param ssid
     * @param accessToken
     * @param cb
     * @param mgr
     * @param lastWiFiEnabled
     */
    void _doAuthInHospitalNetwork(final String ssid, final String accessToken, final OnWiFiEnabled cb, final WifiManager mgr, final int networkId, final boolean lastWiFiEnabled) {
        _testAuthLogon(new ValueCallback<Boolean>() {
            @Override
            public void onReceiveValue(Boolean value) {
                if (value) { // 可以上内网
                    //向服务器请求验证参数
                    _makeAuthInHospitalNetwork(ssid, accessToken, new OnMakeAuthResult() {
                        @Override
                        public void onResult(JSONObject res) {
                            WifiInfo c = mgr.getConnectionInfo();
                            String bssid = null;
                            int networkId = -1;
                            if (c != null) {
                                bssid = c.getBSSID();
                                networkId = c.getNetworkId();
                            }
                            _doAuth(res, bssid, networkId, new OnWiFiEnabled() { //执行认证
                                @Override
                                public void onEnabled() {
                                    cb.onEnabled();
                                }

                                @Override
                                public void onFailed(String msg) {
                                    if (lastWiFiEnabled) {
                                        if (mgr.getWifiState() == WifiManager.WIFI_STATE_DISABLED) {
                                            mgr.setWifiEnabled(true);
                                        }
                                    }
                                    cb.onFailed(msg);
                                }
                            });
                        }

                        @Override
                        public void onFailed(String msg) {
                            if (lastWiFiEnabled) {
                                if (mgr.getWifiState() == WifiManager.WIFI_STATE_DISABLED) {
                                    mgr.setWifiEnabled(true);
                                }
                            }
                            cb.onFailed(msg);
                        }
                    });
                } else { // 内网不能上
                    mgr.disableNetwork(networkId);
                    mgr.removeNetwork(networkId);
                    _doAuth(ssid, accessToken, cb, mgr, lastWiFiEnabled);
                }
            }
        });
    }

    /**
     * 连着流量进行验证Wifi
     *
     * @param ssid
     * @param accessToken
     * @param cb
     * @param mgr
     * @param lastWiFiEnabled
     */
    void _doAuth(final String ssid, final String accessToken, final OnWiFiEnabled cb, final WifiManager mgr, final boolean lastWiFiEnabled) {
        //向服务器请求验证参数
        _makeAuth(ssid, accessToken, new OnMakeAuthResult() {
            @Override
            public void onResult(final JSONObject res) { //验证参数请求成功, 连接WiFi
                //开启WiFi
                _waitWiFiEnabled(50, new OnWiFiEnabled() {
                    @Override
                    public void onEnabled() { //WiFi 启用成功, 执行连接
                        _doConnectWiFi(ssid, new OnWiFiEnabled() {
                            @Override
                            public void onEnabled() { //连接成功, 执行验证
                                // 验证当前所连接网络是否可以上网
                                _testIfNeedLogon(new ValueCallback<Boolean>() {
                                    @Override
                                    public void onReceiveValue(Boolean value) {
                                        if (!value) {
                                            WifiInfo c = mgr.getConnectionInfo();
                                            String bssid = null;
                                            int networdId = -1;
                                            if (c != null) {
                                                bssid = c.getBSSID();
                                                networdId = c.getNetworkId();
                                            }
                                            _doAuth(res, bssid, networdId, new OnWiFiEnabled() { //执行认证
                                                @Override
                                                public void onEnabled() {
                                                    cb.onEnabled();
                                                }

                                                @Override
                                                public void onFailed(String msg) {
                                                    if (lastWiFiEnabled) {
                                                        if (mgr.getWifiState() == WifiManager.WIFI_STATE_DISABLED) {
                                                            mgr.setWifiEnabled(true);
                                                        }
                                                    }
                                                    cb.onFailed(msg);
                                                }
                                            });
                                        } else {
                                            cb.onEnabled();
                                        }
                                    }
                                });
                            }

                            @Override
                            public void onFailed(String msg) {
                                if (lastWiFiEnabled) {
                                    if (mgr.getWifiState() == WifiManager.WIFI_STATE_DISABLED) {
                                        mgr.setWifiEnabled(true);
                                    }
                                }
                                cb.onFailed(msg);
                            }
                        });
                    }

                    @Override
                    public void onFailed(String msg) {
                        if (lastWiFiEnabled) {
                            if (mgr.getWifiState() == WifiManager.WIFI_STATE_DISABLED) {
                                mgr.setWifiEnabled(true);
                            }
                        }
                        cb.onFailed(msg);
                    }
                });
            }

            @Override
            public void onFailed(String msg) {
                if (lastWiFiEnabled) {
                    mgr.setWifiEnabled(true);
                }
                cb.onFailed(msg);
            }
        });
    }

    /**
     * WiFi操作响应接口
     */
    public interface OnWiFiEnabled {
        void onEnabled();

        void onFailed(String msg);
    }

    public interface ValueCallback<T> {
        public void onReceiveValue(T value);
    }

    void _waitWiFiEnabled(final int counter, final OnWiFiEnabled cb) {
        WifiManager mgr = ((WifiManager) _ctx.getSystemService(Context.WIFI_SERVICE));
        if (mgr.getWifiState() == WifiManager.WIFI_STATE_ENABLED) {
            cb.onEnabled();
        } else {
            mgr.setWifiEnabled(true);
            if (counter < 0) {
                cb.onFailed("Timeout to enable WiFi");
                return;
            }
            _handler2.postDelayed(new Runnable() {
                @Override
                public void run() {
                    _waitWiFiEnabled(counter - 1, cb);
                }
            }, 100);
        }
    }

    void _waitWiFiDiabled(final int counter, final OnWiFiEnabled cb) {
        WifiManager mgr = ((WifiManager) _ctx.getSystemService(Context.WIFI_SERVICE));
        if (mgr.getWifiState() == WifiManager.WIFI_STATE_DISABLED) {
            cb.onEnabled();
        } else {
            int id = mgr.getConnectionInfo().getNetworkId();
            if (id == -1) {
                cb.onEnabled();
            } else {
                mgr.setWifiEnabled(false);
                if (counter < 0) {
                    cb.onFailed("Timeout to disable WiFi");
                    return;
                }
                _handler2.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        _waitWiFiEnabled(counter - 1, cb);
                    }
                }, 100);
            }
        }
    }


    /**
     * 等待WiFi连接到特定的网络
     *
     * @param counter
     * @param netId
     * @param cb
     */
    void _waitWiFiConnected(final int counter, final int netId, final OnWiFiEnabled cb) {
        WifiManager mgr = ((WifiManager) _ctx.getSystemService(Context.WIFI_SERVICE));
        WifiInfo c = mgr.getConnectionInfo();
        if (c != null) { //连接成功了
            if (c.getNetworkId() != netId) {
                mgr.enableNetwork(netId, true);
            } else if (getNetworkType(_ctx) == WIFI_NETWORK
                    && c.getSupplicantState() == SupplicantState.COMPLETED) { //连接到对应的网络了
                _handler2.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        cb.onEnabled();
                    }
                }, 1500);
                return;
            }
        }
        if (counter < 0) {
            cb.onFailed("Timeout to enable WiFi");
            return;
        }
        _handler2.postDelayed(new Runnable() {
            @Override
            public void run() {
                _waitWiFiConnected(counter - 1, netId, cb);
            }
        }, 100);
    }

    void _doConnectWiFi(String ssid, final OnWiFiEnabled cb) {
        WifiManager mgr = ((WifiManager) _ctx.getSystemService(Context.WIFI_SERVICE));
        List<WifiConfiguration> configs = mgr.getConfiguredNetworks();

        WifiConfiguration targetCfg = null;
        for (WifiConfiguration config : configs) {
            if (config.SSID.equals("\"" + ssid + "\"")) {
                targetCfg = config;
                break;
            }
        }
        boolean rmFailed = false;
        if (targetCfg != null) {
            if (!mgr.removeNetwork(targetCfg.networkId)) {
                rmFailed = true;
            }
        }
        int netId;
        if (rmFailed) {
            netId = targetCfg.networkId;
        } else {
            targetCfg = new WifiConfiguration();
            targetCfg.allowedAuthAlgorithms.clear();
            targetCfg.allowedGroupCiphers.clear();
            targetCfg.allowedKeyManagement.clear();
            targetCfg.allowedPairwiseCiphers.clear();
            targetCfg.allowedProtocols.clear();
            targetCfg.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
            targetCfg.SSID = "\"" + ssid + "\"";
            netId = mgr.addNetwork(targetCfg);
            if (netId == -1) { //添加失败, 重新检索
                configs = mgr.getConfiguredNetworks();
                targetCfg = null;
                for (WifiConfiguration config : configs) {
                    if (config.SSID.equals("\"" + ssid + "\"")) {
                        targetCfg = config;
                        netId = targetCfg.networkId;
                        break;
                    }
                }
            }
            if (netId == -1) { //添加不成，也寻找不到，失败
                _handler2.post(new Runnable() {
                    @Override
                    public void run() {
                        cb.onFailed("Failed to addNetwork");
                    }
                });
                return;
            }
        }
        if (!mgr.enableNetwork(netId, true)) {
            _handler2.post(new Runnable() {
                @Override
                public void run() {
                    cb.onFailed("Failed to enableNetwork");
                }
            });
            return;
        }
        _waitWiFiConnected(50, netId, cb);
    }

    void _doAuth(JSONObject res, final String bssid, final int networdId, final OnWiFiEnabled cb) {
        try {
            final String url = res.getString("url");
            final String method = res.getString("method");
            final String params = res.optString("params", "");
            final String connId = res.getString("connId");
            JSONObject headers = res.optJSONObject("headers");
            final Map<String, String> headersMap = new HashMap<>();
            if (headers != null) {
                Iterator<String> k = headers.keys();
                while (k.hasNext()) {
                    String name = k.next();
                    headersMap.put(name, headers.getString(name));
                }
            }

            new AsyncTask<Void, Void, String>() {
                @Override
                protected String doInBackground(Void... p) {
                    if (method.equals("POST")) {
                        return httpPOST(_ctx, url, params, headersMap, networdId);
                    } else {
                        return httpGET(_ctx, url, headersMap, networdId);
                    }
                }

                @Override
                protected void onPostExecute(final String s) {
                    if (s == null) {
                        cb.onFailed("内网认证服务器认证失败");
                        return;
                    }
                    //进一步验证是否连接成功
                    _handler2.postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            _doSaveResult(connId, bssid, 200, s, cb);
                        }
                    }, 1000);
                }
            }.execute();
        } catch (Throwable e) {
            e.printStackTrace();
            cb.onFailed("非法的WiFi认证服务");
        }
    }

    /**
     * 验证是否认证成功
     *
     * @param connId
     * @param bssid
     * @param statusCode
     * @param body
     * @param cb
     */
    void _doSaveResult(final String connId, String bssid, int statusCode, String body, final OnWiFiEnabled cb) {
        String params = "connId=" + connId + "&statusCode=" + statusCode;
        if (bssid != null) {
            params += "&BSSID=" + URLEncoder.encode(bssid);
        }
        if (body == null) {
            body = "";
        }
        params += "&body=" + URLEncoder.encode(body);
        final String params2 = params;
        new AsyncTask<Void, Void, String>() {
            @Override
            protected String doInBackground(Void... p) {
                return httpPOST(_serverUrl + "/connection/result", params2, null);
            }

            @Override
            protected void onPostExecute(String s) {
                if (s == null) {
                    _testIfNeedLogon(new ValueCallback<Boolean>() {
                        @Override
                        public void onReceiveValue(Boolean value) {
                            if (value) { // 可以上外网
                                cb.onEnabled();
                            } else { // 不能上网
                                cb.onFailed("连接WiFi认证服务失败");
                            }
                        }
                    });
                    return;
                }
                if (s.equals("true")) {
                    cb.onEnabled();
                } else {
                    cb.onFailed("WiFi自动认证失败");
                }
            }
        }.execute();
    }

    //下一轮扫描
    void _next(int delay) {
        _running = false;
        _handler.removeCallbacksAndMessages(null);
        if (!_started) return;
        _handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                _doRun();
            }
        }, delay == -1 ? SCAN_DELAY : delay);
    }

    //下一轮扫描
    void _next() {
        _next(-1);
    }

    /**
     * 去除引号
     *
     * @param v
     * @return
     */
    static String dequote(String v) {
        if (v.substring(0, 1) == "\"") {
            v = v.substring(1);
        }
        if (v.substring(v.length() - 1, v.length()) == "\"") {
            v = v.substring(0, v.length() - 1);
        }
        return v;
    }

    //扫描可免认证连接的
    void _scanAvl(WifiManager mgr) {
        mgr.startScan();
        List<ScanResult> wifis = mgr.getScanResults();
        if (wifis == null || wifis.size() == 0) {
            for (OnWiFiAvailableListener cb : _handlers) {
                cb.onNoWiFi();
            }
            _next(6 * 1000);
            return;
        }
        Set<String> wifis_set = new HashSet<>();
        String params = null;
        for (int i = 0; i < wifis.size(); ++i) {
            ScanResult sr = wifis.get(i);
            if (sr.SSID.isEmpty()) continue;
            if (wifis_set.contains(sr.SSID)) continue;
            wifis_set.add(sr.SSID);
            Log.v("WiFi", "SSID: " + sr.SSID + ", capabilities: " + sr.capabilities);
            if (sr.capabilities.contains("WPA") || sr.capabilities.contains("WEP") || sr.capabilities.contains("wpa") || sr.capabilities.contains("wep"))
                continue; //旁路加密的WiFi
            if (params == null) {
                params = "SSID=" + URLEncoder.encode(dequote(sr.SSID));
            } else {
                params += "&SSID=" + URLEncoder.encode(dequote(sr.SSID));
            }
        }
        if (params == null) {
            _next();
            return;
        }
        final String params2 = params;
        new AsyncTask<Void, Void, String>() {
            @Override
            protected String doInBackground(Void... params) {
                return httpGET(_serverUrl + "/list?" + params2, null);
            }

            @Override
            protected void onPostExecute(String s) {
                if (s == null) {
                    _next();
                    return;
                }
                try {
                    JSONArray ja = new JSONArray(s);
                    if (ja.length() != 0) {
                        List<String> wifis = new LinkedList<String>();
                        for (int i = 0; i < ja.length(); ++i) {
                            wifis.add(ja.getString(i));
                        }
                        if (wifis.size() != 0) {
                            if (_started) {
                                for (OnWiFiAvailableListener cb : _handlers) {
                                    cb.onWiFiAvailable(wifis);
                                }
                            }
                        }
                    }
                } catch (Throwable e) {
                    e.printStackTrace();
                }
                _next();
            }
        }.execute();
    }

    /**
     * 测试当前的WiFi连接是否需要Portal认证
     */
    void _testIfNeedLogon() {
        new AsyncTask<Void, Void, Integer>() {
            @Override
            protected Integer doInBackground(Void... params) {
                return httpGETCode("http://g.cn/generate_204");
            }

            @Override
            protected void onPostExecute(Integer code) {
                int iCode = code;
                if (iCode != 204) { //需要WiFi认证,
                    _testAuthLogon(new ValueCallback<Boolean>() {
                        @Override
                        public void onReceiveValue(Boolean value) {
                            if (value) {
                                WifiManager mgr = (WifiManager) _ctx.getSystemService(Context.WIFI_SERVICE);
                                _scanAvl(mgr);
                            } else {
                                WifiManager mgr = (WifiManager) _ctx.getSystemService(Context.WIFI_SERVICE);
                                WifiInfo info = mgr.getConnectionInfo();
                                if (info != null && info.getNetworkId() != -1) { //WiFi已经连接, 检测是否可以连接网络
                                    mgr.disableNetwork(info.getNetworkId());
                                    mgr.removeNetwork(info.getNetworkId());
                                    _next(10 * 1000);
                                } else {
                                    _next(10 * 1000);
                                }
                            }
                        }
                    });
                } else { //已经可以上网
                    for (OnWiFiAvailableListener cb : _handlers) {
                        cb.onWiFiConnected();
                    }
                    _next();
                }
            }
        }.execute();
    }

    /**
     * 测试当前的WiFi链接是否可以链接内网
     */
    void _testAuthLogon(final ValueCallback<Boolean> callback) {
        new AsyncTask<Void, Void, Integer>() {
            @Override
            protected Integer doInBackground(Void... params) {
                return httpGETCode(_serverUrl + "list");
            }

            @Override
            protected void onPostExecute(Integer code) {
                int iCode = code;
                if (iCode != 200) { //需要WiFi认证,
                    callback.onReceiveValue(false);
                } else { //已经可以内网
                    callback.onReceiveValue(true);
                }
            }
        }.execute();
    }

    /**
     * 测试所连的WiFi是否可以上外网（针对认证过的）
     *
     * @param callback
     */
    void _testIfNeedLogon(final ValueCallback<Boolean> callback) {
        new AsyncTask<Void, Void, Integer>() {
            @Override
            protected Integer doInBackground(Void... params) {
                return httpGETCode("http://g.cn/generate_204");
            }

            @Override
            protected void onPostExecute(Integer code) {
                int iCode = code;
                if (iCode != 204) { //需要WiFi认证,
                    callback.onReceiveValue(false);
                } else { //已经可以外网
                    callback.onReceiveValue(true);
                }
            }
        }.execute();
    }

    void _doRun() {
        if (_running || !_started) return;
        _running = true;
        WifiManager mgr = (WifiManager) _ctx.getSystemService(Context.WIFI_SERVICE);
        if (mgr.isWifiEnabled()) {
            WifiInfo info = mgr.getConnectionInfo();
            if (getNetworkType(_ctx) == WIFI_NETWORK && info != null && info.getSupplicantState() == SupplicantState.COMPLETED) { //WiFi已经连接, 检测是否可以连接网络
                _testIfNeedLogon();
                return;
            }
        }

        if (mgr.getWifiState() == WifiManager.WIFI_STATE_DISABLED) {
            boolean status = mgr.setWifiEnabled(true);
            if (!status) {
                for (OnWiFiAvailableListener cb : _handlers) {
                    cb.wifiNoEnable();
                }
                stop();
                return;
            }
            _next(6 * 1000);
            return;
        }
        _scanAvl(mgr);
    }

    /***
     * 1 ：wifi、2:移动网络 、3：有线网络 0、无网络
     */
    private int getNetworkType(Context context) {
        ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
        if (networkInfo != null && networkInfo.isAvailable()) {
            if (networkInfo.getType() == ConnectivityManager.TYPE_WIFI) {
                //Wifi
                return WIFI_NETWORK;
            } else if (networkInfo.getType() == ConnectivityManager.TYPE_MOBILE) {
                //3G
                return G_NETWORK;
            } else if (networkInfo.getType() == ConnectivityManager.TYPE_ETHERNET) {
                //有线
                return LINE_NETWORK;
            }
        }
        return NO_NETWORK;
    }
}
